package org.jeecg;

import com.xkcoding.justauth.autoconfigure.JustAuthAutoConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;

/**
* 单体启动类
* 报错提醒: 未集成mongo报错，可以打开启动类上面的注释 exclude={MongoAutoConfiguration.class}
*/
@Slf4j
@SpringBootApplication
@ImportAutoConfiguration(JustAuthAutoConfiguration.class)  // spring boot 3.x justauth 兼容性处理
//@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class})
public class JeecgSystemApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(JeecgSystemApplication.class);
    }

    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext application = SpringApplication.run(JeecgSystemApplication.class, args);
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        String path = oConvertUtils.getString(env.getProperty("server.servlet.context-path"));
        log.info("\n----------------------------------------------------------\n\t" +
                "Application Jeecg-Boot is running! Access URLs:\n\t" +
                "Local: \t\thttp://localhost:" + port + path + "/\n\t" +
                "External: \thttp://" + ip + ":" + port + path + "/\n\t" +
                "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n" +
                "----------------------------------------------------------");

//        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
//            System.out.println("执行关闭清理工作...");
//            // 在这里执行清理逻辑
//        }));
//        String[] newArgs = args.clone();
//        int defaultPort = 8081;
//        boolean needChangePort = false;
//
//        // 检查默认端口是否被占用
//        if (isPortInUse(defaultPort)) {
//            // 创建新的参数数组，添加备用端口参数
//            newArgs = new String[args.length + 1];
//            System.arraycopy(args, 0, newArgs, 0, args.length);
//            newArgs[newArgs.length - 1] = "--server.port=9090";
//            needChangePort = true;
//        }
//
//        // 启动Spring Boot应用
//        ConfigurableApplicationContext run = SpringApplication.run(JeecgSystemApplication.class, newArgs);
//
//        // 只有在Linux/macOS系统且需要切换端口时才执行
//        if (needChangePort && !isWindows()) {
//            try {
//                // 杀死占用端口的进程
//                killProcessUsingPort(defaultPort);
//
//                // 等待直到端口被释放
//                while (isPortInUse(defaultPort)) {
//                    Thread.sleep(100); // 避免CPU占用过高
//                }
//
//                // 获取Web服务器工厂并重新配置端口
//                reconfigureToDefaultPort(run, defaultPort);
//            } catch (Exception ignored) {
//                // 记录日志或处理异常
//            }
//        }
    }

    // 判断是否是Windows系统
    private static boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("win");
    }

    // 杀死占用指定端口的进程
    private static void killProcessUsingPort(int port) throws InterruptedException, IOException {
        String command;
        if (isMac()) {
            command = String.format("lsof -i tcp:%d | grep LISTEN | awk '{print $2}' | xargs kill -9", port);
        } else {
            // 假设是Linux系统
            command = String.format("fuser -k -n tcp %d", port);
        }
        Runtime.getRuntime().exec(new String[]{"sh", "-c", command}).waitFor();
    }

    // 判断是否是Mac系统
    private static boolean isMac() {
        return System.getProperty("os.name").toLowerCase().contains("mac");
    }

    // 重新配置到默认端口
    private static void reconfigureToDefaultPort(ConfigurableApplicationContext context, int port) {
        ServletWebServerFactory webServerFactory = getWebServerFactory(context);
        ((TomcatServletWebServerFactory) webServerFactory).setPort(port);
        WebServer webServer = webServerFactory.getWebServer(invokeSelfInitialize(((ServletWebServerApplicationContext) context)));
        webServer.start();
        ((ServletWebServerApplicationContext) context).getWebServer().stop();
    }

    // 获取Servlet上下文初始化器（反射方式）
    private static ServletContextInitializer invokeSelfInitialize(ServletWebServerApplicationContext context) {
        try {
            Method method = ServletWebServerApplicationContext.class.getDeclaredMethod("getSelfInitializer");
            method.setAccessible(true);
            return (ServletContextInitializer) method.invoke(context);
        } catch (Exception e) {
            throw new RuntimeException("Failed to get self initializer", e);
        }
    }

    // 检查端口是否被占用
    private static boolean isPortInUse(int port) {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            return false;
        } catch (IOException e) {
            return true;
        }
    }

    // 获取Web服务器工厂Bean
    private static ServletWebServerFactory getWebServerFactory(ConfigurableApplicationContext context) {
        String[] beanNames = context.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
        return context.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    }



}